#include <opencv2/opencv.hpp>
#include <iostream>

using namespace cv;
using namespace std;


/**
 区域生长
 img为原图像，result为经区域生长后的图像，seed为初始种子点，threshold为阈值
 输入种子点超出范围返回false
 */
bool regionGrowing(Mat img, Mat &result, Point2i seed, int threshold){
    result = Mat::zeros(img.size(), CV_8UC1); //背景全部设置为黑
//    输入种子点超出范围返回false
    if (seed.x < 0 || seed.y < 0 || seed.y > img.rows-1 || seed.x > img.cols-1) {
        return false;
    }
    
    vector<Point2i> seeds; //种子点集
    seeds.push_back(seed); //压入初始种子点
    result.ptr<uchar>(seed.y)[seed.x] = 255; //种子点设置为白
    int growDirections[8][2] = {{-1,-1}, {0,-1}, {1,-1}, {-1,0}, {1,0}, {-1,1}, {0,1}, {1,1}}; //生长方向
    
//    开始生长
    while (!seeds.empty()) {
        // 取出一个种子点作为现在循环的初始种子点
        Point2i seed_current = seeds.back();
        seeds.pop_back();
        
        // 遍历各生长方向的邻点
        for (int i = 0; i < 8; i++) {
            Point2i neighborPoint = {seed_current.x + growDirections[i][0], seed_current.y + growDirections[i][1]}; //邻点
            if (neighborPoint.x < 0 || neighborPoint.y < 0 || neighborPoint.x > img.cols-1 || neighborPoint.y > img.rows-1) { //邻点超出范围
                continue;
            }
            if ((result.ptr<uchar>(neighborPoint.y)[neighborPoint.x] == 0) && abs(img.ptr<uchar>(neighborPoint.y)[neighborPoint.x] - img.ptr<uchar>(seed.y)[seed.x]) < threshold) {
                // 设置为种子点
                result.ptr<uchar>(neighborPoint.y)[neighborPoint.x] = 255; //设置为白色
                seeds.push_back(neighborPoint); //压入种子集
            }
        }
    }
    
    return true;
}

int main() {
    Mat img, result;
    img = imread("/home/eric/a_ros_ws/jtrob_simulation/src/map-division/map_division/img/demo.png", IMREAD_GRAYSCALE); //从文件中加载灰度图像

//    读取图片失败，则停止
    if (img.empty()) {
        printf("读取图像文件失败");
        system("pause");
        return -1;
    }
    
//    输入初始种子点
    cout << "Select a point as seed from [" << img.rows-1 << ", " << img.cols-1 << "]" << endl;
    int seed_row, seed_col;
    cout << "row";
    cin >> seed_row;
    cout << "col";
    cin >> seed_col;
    Point2i seed;
    seed.x = seed_col;
    seed.y = seed_row;
    
//    区域生长
    int threshold = 20;
    regionGrowing(img, result, seed, threshold); //区域生长
    
//    图像显示
    imshow("img",img);
    imshow("result",result);
    imwrite("result.jpg", result);
    waitKey(); //等待键值输入
    
    return 0;
}